﻿using System;
using System.Collections;
using System.Text;
using System.Collections.Generic;

namespace BizElements.Generator.OrmComponents
{
    /// <summary>
    /// Provides common operations for array and list manipulation (conversions, sets...).
    /// </summary>
    internal static class ArrayUtil
    {
        #region Find.

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire collection.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The first element that matches the conditions defined by the specified predicate, if found; otherwise, the default value for type TElement.</returns>
        public static TElement Find<TElement>(IEnumerable collection, Predicate<TElement> match)
        {
            foreach (TElement obj in collection)
            {
                if (match(obj))
                    return obj;
            }

            return default(TElement);
        }

        #endregion

        #region FindAll.

        /// <summary>
        /// Retrieves all the elements that match the conditions defined by the specified predicate.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>A list containing all the elements that match the conditions defined by the specified predicate, if found; otherwise, an empty list.</returns>
        public static TList FindAll<TList, TElement>(IEnumerable collection, Predicate<TElement> match)
            where TList : IList, new()
        {
            TList matches = new TList();
            foreach (TElement obj in collection)
            {
                if (match(obj))
                    matches.Add(obj);
            }

            return matches;
        }

        #endregion

        #region IsNullOrEmpty.

        /// <summary>
        /// Checks whether the specified collection is a null reference or an empty collection.
        /// </summary>
        /// <param name="collection">Collection to check.</param>
        /// <returns><b>true</b> if the provided collection is <b>null</b> or empty; otherwise, false.</returns>
        public static bool IsNullOrEmpty(IEnumerable collection)
        {
            if (collection == null)
                return true;

            IEnumerator enumerator = collection.GetEnumerator();
            bool isEmpty = !enumerator.MoveNext();
            return isEmpty;
        }

        #endregion

        #region Concat.

        /// <summary>
        /// Concatenates the string representations of the elements in the specified list.  
        /// </summary>
        /// <param name="list">A list of objects.</param>
        /// <param name="delimiter">Optional string which is used to delimit objects. Nullable.</param>
        /// <returns>The concatenated and delimited string representations of the values of the elements in the list.</returns>
        public static string Concat(IEnumerable list, string delimiter)
        {
            if (delimiter == null)
                delimiter = "";

            StringBuilder str = new StringBuilder();
            foreach (object element in list)
            {
                str.Append(element);
                str.Append(delimiter);
            }

            if (str.Length >= delimiter.Length)
                str.Remove(str.Length - delimiter.Length, delimiter.Length);

            return str.ToString();
        }

        #endregion

        #region FindIndex.

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the entire collection.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.</returns>
        public static int FindIndex<TElement>(IEnumerable collection, Predicate<TElement> match)
        {
            int index = 0;
            foreach (TElement obj in collection)
            {
                if (match(obj))
                    return index;

                index++;
            }

            return -1;
        }

        #endregion

        #region Exists.

        /// <summary>
        /// Determines whether the collection contains elements that match the conditions defined by the specified predicate.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>true if the collection contains one or more elements that match the conditions defined by the specified predicate; otherwise, false.</returns>
        public static bool Exists<TElement>(IEnumerable collection, Predicate<TElement> match)
        {
            foreach (TElement obj in collection)
            {
                if (match(obj))
                    return true;
            }

            return false;
        }

        #endregion

        #region Count.

        /// <summary>
        /// Returns the number of elements that match the conditions defined by the specified predicate.  
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>Number of elements that match the conditions defined by the specified predicate.</returns>
        public static int Count<TElement>(IEnumerable collection, Predicate<TElement> match)
        {
            int count = 0;
            foreach (TElement obj in collection)
            {
                if (match(obj))
                    count++;
            }

            return count;
        }

        #endregion
    }
}